import logging
import multiprocessing

from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.schedulers.background import BackgroundScheduler
from flask_apscheduler import APScheduler

from common.exchanges.manager import ExchangeServiceManager
from common.models.account import Account
from web import session_scope, settings
from web.service.account import AccountService

logger = logging.getLogger('scheduler')
_scheduler = BackgroundScheduler(executors={
    'default': ThreadPoolExecutor(max_workers=8 * multiprocessing.cpu_count())
}, logger=logger)


scheduler = APScheduler(scheduler=_scheduler)


def init_scheduler(app):
    scheduler.init_app(app)
    # 启动用户ExchangeService
    _scheduler.add_job(ensure_user_service_run, trigger='date', id='ensure_user_service_run')

    # 合约数据周期刷新
    _scheduler.add_job(refresh_instruments_info, trigger='interval', seconds=600)
    # 立即缓存
    _scheduler.add_job(refresh_instruments_info, trigger='date', )

    logger.info('scheduler is inited.')
    scheduler.start()


def refresh_instruments_info():
    for exchange in settings.SUPPORT_EXCHANGES:
        try:
            pub_service = ExchangeServiceManager.pub_factory(exchange)
            pub_service.instruments_info(use_cache=False)
            logger.info(f'refresh {exchange} instruments info success')
        except Exception as e:
            logger.exception(f'refresh {exchange} instruments info except: {e}')


def ensure_user_service_run():
    logger.info('ensure_user_service_run begin execute...')
    with session_scope() as session:
        accounts = Account.query.all()
        for account in accounts:
            try:
                auth_info = AccountService.account2auth_info(account)
                service = ExchangeServiceManager.pri_factory(account.exchange, auth_info, )
                service.ensure_catcher_run()
                logger.info(f'account {account.id} user data catcher is running.')
            except Exception as e:
                logger.error(f'ensure account {account.id} user data service run failed: {e}')
